package com.sew.sewweb.common.utils;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.*;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import com.thoughtworks.xstream.XStream;

import cn.hutool.core.util.StrUtil;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

public class XmlUtils {
	 private final static String XML_DECLARATION = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
	/**
	 * 遍历 Map 并构建 xml 数据
	 *
	 * @param params 需要遍历的 Map
	 * @param prefix xml 前缀
	 * @param suffix xml 后缀
	 * @return
	 */
	public static String toxmlFromMap(Map<String, String> params, String prefix, String suffix) {
		StringBuilder xml = new StringBuilder();
		if (StrUtil.isNotEmpty(prefix)) {
			xml.append(prefix);
		}
		for (Map.Entry<String, String> entry : params.entrySet()) {
			String key = entry.getKey();
			String value = entry.getValue();
			// 略过空值
			if (StrUtil.isEmpty(value)) {
				continue;
			}
			xml.append("<").append(key).append(">");
			xml.append(entry.getValue());
			xml.append("</").append(key).append(">");
		}
		if (StrUtil.isNotEmpty(suffix)) {
			xml.append(suffix);
		}
		return xml.toString();
	}

	/**
     * 针对支付的 xml，没有嵌套节点的简单处理
     *
     * @param xmlStr xml 字符串
     * @return 转化后的 Map
     */
    public static Map<String, String> xmlToMap(String xmlStr) {
        XmlHelper xmlHelper = XmlHelper.of(xmlStr);
        return xmlHelper.toMap();
    }

    private XmlUtils() {
    }

    /**
     * 序列化XML
     *
     * @param obj
     * @param clazz
     * @return
     */
    public static <T> String toXML(Object obj) {
        XStream stream = getXStream();
        stream.processAnnotations(obj.getClass());
        return new StringBuffer(XML_DECLARATION).append(stream.toXML(obj)).toString();
    }

    /**
     * 反序列化XML
     *
     * @param xmlStr
     * @param clazz
     * @return
     */
    public static <T> T fromXML(String xmlStr, Class<T> clazz) {
        XStream stream = getXStream();
        stream.processAnnotations(clazz);
        Object obj = stream.fromXML(xmlStr);
        try {
            return clazz.cast(obj);
        } catch (ClassCastException e) {
            return null;
        }
    }

    /**
     * 获取指定节点的值
     *
     * @param xpath
     * @param params
     * @return
     */
    public static String getNodeValue(String xpath, String dataStr) {
        try {
            // 将字符串转为xml
            Document document = DocumentHelper.parseText(dataStr);
            // 查找节点
            Element element = (Element) document.selectSingleNode(xpath);
            if (element != null) {
                return element.getStringValue();
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 获取Xstream实例
     *
     * @return
     */
    public static XStream getXStream() {
        return new XStream();
    }

    /**
     * 将Map转换为XML,Map可以多层转
     * @param params 需要转换的map。
     * @param parentName 就是map的根key,如果map没有根key,就输入转换后的xml根节点。
     * @return String-->XML
     */
    @SuppressWarnings("unchecked")
    public static String createXmlByMap(Map<String, Object> map, String parentName) {
        //获取map的key对应的value
        Map<String, Object> rootMap=(Map<String, Object>)map.get(parentName);
        if (rootMap==null) {
            rootMap=map;
        }
        Document doc = DocumentHelper.createDocument();
        //设置根节点
        doc.addElement(parentName);
        //不为空给根节点设置属性
//        if(!maps.isEmpty()){
//            Set set = maps.keySet();
//            for(Object obj: set){
//                rss.addAttribute(obj.toString(), maps.get(obj.toString()));
//            }
//        }

        String xml = iteratorXml(doc.getRootElement(), parentName, rootMap);
        return xml;
    }
    /**
     * 循环遍历params创建xml节点
     * @param element 根节点
     * @param parentName 子节点名字
     * @param params map数据
     * @return String-->Xml
     */
    @SuppressWarnings("unchecked")
    public static String iteratorXml(Element element, String parentName, Map<String, Object> params) {
        Element e = element.addElement(parentName);
        Set<String> set = params.keySet();
        for (Iterator<String> it = set.iterator(); it.hasNext();) {
            String key = (String) it.next();
            if (params.get(key) instanceof Map) {
                iteratorXml(e, key, (Map<String, Object>) params.get(key));
            } else if (params.get(key) instanceof List) {
                List<Object> list = (ArrayList<Object>) params.get(key);
                for (int i = 0; i < list.size(); i++) {
                    if (list.get(i) instanceof Map) {                           //判断是否最底层的list
                        iteratorXml(e, key, (Map<String, Object>) list.get(i));
                    }else {
                        e.addElement(key).addText((String) list.get(i));
                    }
                }
            } else {
                String value = params.get(key) == null ? "" : params.get(key).toString();
                e.addElement(key).addText(value);
                // e.addElement(key).addCDATA(value);
            }
        }
        return e.asXML();
    }
    /**
     * 格式化xml
     * @param xml
     * @return
     */
    public static String formatXML(String xml) {
        String requestXML = null;
        XMLWriter writer = null;
        Document document = null;
        try {
            SAXReader reader = new SAXReader();
            document = reader.read(new StringReader(xml));
            if (document != null) {
                StringWriter stringWriter = new StringWriter();
                OutputFormat format = new OutputFormat("", true);// 格式化，每一级前的空格
                format.setEncoding("utf-8"); //后添加编码格式
                format.setNewLineAfterDeclaration(false); // xml声明与内容是否添加空行
                format.setSuppressDeclaration(false); // 是否设置xml声明头部 false：添加
                format.setNewlines(true); // 设置分行
                writer = new XMLWriter(stringWriter, format);
                writer.write(document);
                writer.flush();
                requestXML = stringWriter.getBuffer().toString();
            }
            return requestXML;
        } catch (Exception e1) {
            e1.printStackTrace();
            return null;
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                }
            }
        }
    }
    /**
     * 第二种
     * 手动组装map转为string
     * @param map
     * @return
     */
    public static String moveMapToXML(Map<?, ?> map) {
        StringBuffer sb = new StringBuffer();
        mapToXML(map, sb);
        return formatXML(sb.toString());
    }
    /**
     *
     * @param map 循环遍历map节点和value
     * @param sb 输出xml
     */
    private static void mapToXML(Map<?, ?> map, StringBuffer sb) {
        Set<?> set = map.keySet();
        for (Iterator<?> it = set.iterator(); it.hasNext(); ) {
            String key = (String) it.next();
            Object value = map.get(key);
            if (value instanceof HashMap) {
                sb.append("<" + key + ">");
                mapToXML((HashMap<?, ?>) value, sb);
                sb.append("</" + key + ">");
            } else if (value instanceof ArrayList) {
                List<?> list = (ArrayList<?>) map.get(key);
                for (int i = 0; i < list.size(); i++) {
                    sb.append("<" + key + ">");
                    Map<?, ?> hm = (HashMap<?, ?>) list.get(i);
                    mapToXML(hm, sb);
                    sb.append("</" + key + ">");
                }
            } else {
                sb.append("<" + key + ">" + value + "</" + key + ">");
            }
        }

    }
}
